package com.jfinal.plugin.sqlbuilder;

import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.Sqls;
import org.beetl.core.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SqlBuilder {

    public static final Logger log = LoggerFactory.getLogger(SqlBuilder.class);

    private SqlBuilder() {

    }

    private static final Pattern PATTERN = Pattern.compile("#\\((\\w+)(\\(((\\w+ *,? *)+)\\))?\\)");

    /**
     * 构建动态SQL。
     *
     * @param sqlKey SQL模板名称。
     * @param params 执行SQL的参数。
     * @return 构建结果，包含SQL语句和参数值等信息。
     */
    public static Record build(String sqlKey, Map<String, Object> params) {
        String sql = Sqls.get(sqlKey);

        Template template = SqlBuilderPlugin.groupTemplate.getTemplate(sql);
        template.binding(params);
        sql = template.render();

        Matcher matcher = PATTERN.matcher(sql);
        StringBuffer sb = new StringBuffer();
        List<Object> objects = new ArrayList<Object>();
        while (matcher.find()) {
            String key = matcher.group(1);
            if (matcher.group(3) != null) {
                // 函数调用
                IFunction func = SqlBuilderPlugin.FUNCTION_MAP.get(key);
                if (func == null) {
                    throw new RuntimeException("Unknown function: " + key);
                }
                String args = matcher.group(3);
                objects.addAll(func.getParams(args, params));
                matcher.appendReplacement(sb, func.replaceSql(args));
            } else {
                // 普通属性
                if (params.containsKey(key)) {
                    objects.add(params.get(key));
                }
                matcher.appendReplacement(sb, "?");
            }
        }
        matcher.appendTail(sb);

        Record result = new Record()
                .set("sql", sb.toString())
                .set("params", objects.toArray())
                .set("select", sb.substring(0, sql.indexOf("from")))
                .set("sqlExceptSelect", sb.substring(sql.indexOf("from")));
        log.debug("SQL: {}", sb.toString());
        log.debug("Params: {}", objects.toString());
        return result;
    }

}
